<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>sew &amp;mdash; Tom Tildavaan</title>
    <link>https://infosec.press/tildavaan/tag:sew</link>
    <description>asdf</description>
    <pubDate>Sat, 20 Jun 2026 14:15:58 +0000</pubDate>
    <item>
      <title>Smart Customer Mobile API</title>
      <link>https://infosec.press/tildavaan/smart-customer-mobile-api</link>
      <description>&lt;![CDATA[As I was writing this I decided to scan GitHub for the URLs I found so far, and, well, people smarter than me have already written a homeassistant integration against #SEW, but it is a bit different from what I saw in the field:&#xA;&#xA;https://github.com/cnecrea/hidroelectrica&#xA;&#xA;I&#39;d still like to describe how to locate the endpoints and the login process, so here we go...&#xA;&#xA;This is the second post about #SEW SCM API - Smart Customer Mobile API by Smart Energy Water, this time we will learn about different APIs using real world utility websites.&#xA;&#xA;It appears that there are at least two different API &#34;flavors&#34;. The one that uses ModuleName.svc/MethodNameMob naming convention and usually resides under PortalService endpoint, and the newer one, which lives under /API/.&#xA;&#xA;So e.g. Nebraska Public Power District has endpoints at https://onlineaccount.nppd.com/PortalService/, e.g. https://onlineaccount.nppd.com/PortalService/UserLogin.svc/help. Rochester Public Utilities runs a different set of endpoints, with the root at https://connectwith.rpu.com/api.&#xA;&#xA;The endpoints for the latter API can also be browsed at https://scmcx.smartcmobile.com/API/Help/.&#xA;&#xA;Different utilities pay for different set of modules, and here&#39;s some of the modules I have discovered so far:&#xA;&#xA;AdminBilling&#xA;CompareSpending&#xA;ConnectMe&#xA;EnergyEfficiency&#xA;Generation&#xA;Notifications&#xA;Outage&#xA;PaymentGateway&#xA;Usage&#xA;UserAccount&#xA;UserLogin&#xA;&#xA;For /PortalService/ endpoints you can visit BASEURL + /PortalService/ + ModuleName + .svc + /help to get the list of RPC calls you can issue. In order to find out what to send in the requests, you need to look into the calls within the apps for your utility. Note that some utilities opted out of the AES/CBC/PKCS5Padding PasswordPassword encryption, so let&#39;s hope this will be a trend forward. Currently SEW web portals talk to a completely different set of APIs to populate the interface, even though they are querying the same thing.&#xA;&#xA;So to start, here&#39;s how to login to your favorite utility:&#xA;&#xA;from typing import Mapping, Any&#xA;&#xA;import base64&#xA;import json&#xA;import hashlib&#xA;import requests&#xA;import urllib.parse&#xA;&#xA;from Crypto.Cipher import AES&#xA;&#xA;BASEURL = &#34;https://example.com/PortalService&#34;&#xA;&#xA;def encryptquery(&#xA;    params: Mapping[str, str], encryptionkey: str = &#34;PasswordPassword&#34;&#xA;) -  str:&#xA;    &#34;&#34;&#34;Encrypt with AES/CBC/PKCS5Padding.&#34;&#34;&#34;&#xA;    cipher = AES.new(encryptionkey, AES.MODECBC, IV=encryptionkey)&#xA;&#xA;    cleartext = urllib.parse.urlencode(params).encode()&#xA;&#xA;    # PKCS5 Padding - https://www.rfc-editor.org/rfc/rfc8018#appendix-B.2.5&#xA;    paddinglength = 16 - len(cleartext) % 16&#xA;    cleartext += paddinglength * chr(paddinglength).encode()&#xA;&#xA;    return base64.b64encode(cipher.encrypt(cleartext)).decode(&#34;ascii&#34;)&#xA;&#xA;def request(module: str, method: str, data: Mapping[str, Any]) -  Mapping[str, str]:&#xA;    encquery = encryptquery(data)&#xA;    # Or module + &#39;.svc/&#39;&#xA;    url = BASEURL + &#34;/&#34; + module + &#34;/&#34; + method&#xA;&#xA;    resp = requests.post(url, json={&#34;EncType&#34;: &#34;A&#34;, &#34;EncQuery&#34;: encquery})&#xA;    if not resp.ok:&#xA;        raise Exception(resp.statuscode)&#xA;    return resp.json()&#xA;&#xA;passworddigest = hashlib.sha256(&#34;PASSWORD&#34;.encode()).hexdigest()&#xA;Or ValidateUserLoginMob&#xA;response = request(&#xA;    &#34;UserLogin&#34;,&#xA;    &#34;ValidateUserLogin&#34;,&#xA;    {&#34;UserId&#34;: &#34;USERNAME&#34;, &#34;Password&#34;: passworddigest},&#xA;)&#xA;print(response)&#xA;response will contain some object, you will need LoginToken and AccountNumber to proceed with most of the other calls.&#xA;&#xA;It&#39;s a bit awkward that different utilities have different endpoints, which makes creating a universal client challenging, so for now I am researching the ways to get info from the Usage module. The parameters are weird (&#34;type&#34;: &#34;MI&#34;, or &#34;HourlyType&#34;: &#34;H&#34;), but we will get there.]]&gt;</description>
      <content:encoded><![CDATA[<p>As I was writing this I decided to scan GitHub for the URLs I found so far, and, well, people smarter than me have already written a home_assistant integration against <a href="/tildavaan/tag:SEW" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">SEW</span></a>, but it is a bit different from what I saw in the field:</p>
<ul><li><a href="https://github.com/cnecrea/hidroelectrica" rel="nofollow">https://github.com/cnecrea/hidroelectrica</a></li></ul>

<p>I&#39;d still like to describe how to locate the endpoints and the login process, so here we go...</p>

<p>This is the second post about <a href="/tildavaan/tag:SEW" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">SEW</span></a> SCM API – Smart Customer Mobile API by Smart Energy Water, this time we will learn about different APIs using real world utility websites.</p>

<p>It appears that there are at least two different API “flavors”. The one that uses <code>ModuleName.svc/MethodNameMob</code> naming convention and usually resides under <code>PortalService</code> endpoint, and the newer one, which lives under <code>/API/</code>.</p>

<p>So e.g. <a href="https://nppd.com" rel="nofollow">Nebraska Public Power District</a> has endpoints at <code>https://onlineaccount.nppd.com/PortalService/</code>, e.g. <code>https://onlineaccount.nppd.com/PortalService/UserLogin.svc/help</code>. <a href="https://www.rpu.com" rel="nofollow">Rochester Public Utilities</a> runs a different set of endpoints, with the root at <code>https://connectwith.rpu.com/api</code>.</p>

<p>The endpoints for the latter API can also be browsed at <a href="https://scmcx.smartcmobile.com/API/Help/" rel="nofollow">https://scmcx.smartcmobile.com/API/Help/</a>.</p>

<p>Different utilities pay for different set of modules, and here&#39;s some of the modules I have discovered so far:</p>
<ul><li>AdminBilling</li>
<li>CompareSpending</li>
<li>ConnectMe</li>
<li>EnergyEfficiency</li>
<li>Generation</li>
<li>Notifications</li>
<li>Outage</li>
<li>PaymentGateway</li>
<li>Usage</li>
<li>UserAccount</li>
<li>UserLogin</li></ul>

<p>For <code>/PortalService/</code> endpoints you can visit <code>BASE_URL</code> + <code>/PortalService/</code> + <code>ModuleName</code> + <code>.svc</code> + <code>/help</code> to get the list of RPC calls you can issue. In order to find out what to send in the requests, you need to look into the calls within the apps for your utility. Note that some utilities opted out of the AES/CBC/PKCS5Padding <code>PasswordPassword</code> encryption, so let&#39;s hope this will be a trend forward. Currently SEW web portals talk to a completely different set of APIs to populate the interface, even though they are querying the same thing.</p>

<p>So to start, here&#39;s how to login to your favorite utility:</p>

<pre><code class="language-python">from typing import Mapping, Any

import base64
import json
import hashlib
import requests
import urllib.parse

from Crypto.Cipher import AES

BASE_URL = &#34;https://example.com/PortalService&#34;


def _encrypt_query(
    params: Mapping[str, str], encryption_key: str = &#34;PasswordPassword&#34;
) -&gt; str:
    &#34;&#34;&#34;Encrypt with AES/CBC/PKCS5Padding.&#34;&#34;&#34;
    cipher = AES.new(encryption_key, AES.MODE_CBC, IV=encryption_key)

    cleartext = urllib.parse.urlencode(params).encode()

    # PKCS5 Padding - https://www.rfc-editor.org/rfc/rfc8018#appendix-B.2.5
    padding_length = 16 - len(cleartext) % 16
    cleartext += padding_length * chr(padding_length).encode()

    return base64.b64encode(cipher.encrypt(cleartext)).decode(&#34;ascii&#34;)


def request(module: str, method: str, data: Mapping[str, Any]) -&gt; Mapping[str, str]:
    enc_query = _encrypt_query(data)
    # Or module + &#39;.svc/&#39;
    url = BASE_URL + &#34;/&#34; + module + &#34;/&#34; + method

    resp = requests.post(url, json={&#34;EncType&#34;: &#34;A&#34;, &#34;EncQuery&#34;: enc_query})
    if not resp.ok:
        raise Exception(resp.status_code)
    return resp.json()


password_digest = hashlib.sha256(&#34;PASSWORD&#34;.encode()).hexdigest()
# Or ValidateUserLoginMob
response = request(
    &#34;UserLogin&#34;,
    &#34;ValidateUserLogin&#34;,
    {&#34;UserId&#34;: &#34;USERNAME&#34;, &#34;Password&#34;: password_digest},
)
print(response)
</code></pre>

<p><code>response</code> will contain some object, you will need <code>LoginToken</code> and <code>AccountNumber</code> to proceed with most of the other calls.</p>

<p>It&#39;s a bit awkward that different utilities have different endpoints, which makes creating a universal client challenging, so for now I am researching the ways to get info from the <code>Usage</code> module. The parameters are weird (“type”: “MI”, or “HourlyType”: “H”), but we will get there.</p>
]]></content:encoded>
      <guid>https://infosec.press/tildavaan/smart-customer-mobile-api</guid>
      <pubDate>Tue, 15 Apr 2025 23:34:39 +0000</pubDate>
    </item>
    <item>
      <title>Smart Energy Water SCM API Secrets</title>
      <link>https://infosec.press/tildavaan/smart-energy-water-scm-api-secrets</link>
      <description>&lt;![CDATA[Once upon a time I learned about Opower HomeAssistant integration. But my utility does not use Opower, it was using something called &#34;Smart Energy Water&#34;.&#xA;&#xA;Smart Energy Water, or #SEW is a SaaS provider, and they ship the whole thing - the backend, frontend, and the phone apps, the latter under the name SCM, which means Smart Customer Mobile.&#xA;&#xA;So I embarked on a journey to figure out how these phone apps worked and, if successful, get my data out and into homeassistant.&#xA;&#xA;APK&#xA;&#xA;I pulled an APK of my utility from Google Play Store and found that something secret is hidden in a libnative-lib.so binary, under com.sew.scm.gcm.SecureConstant, under a few methods returning String, and some methods that decrypt these strings using a heavily obfuscated set of routines, which essentially XOR&#39;d (in case of Android APK) the values of gcmdefaultsenderid + googleappid + AndroidAppRatingConstantFile, all the values from the strings.xml within the app resources.&#xA;&#xA;One of the decoded tokens contains a key for request encryption. It was ...&#xA;&#xA;PasswordPassword&#xA;&#xA;SCM apps use private APIs. In order to remain private and hard to use the requests are encrypted.&#xA;&#xA;You urlencode the parameters into key=value&amp;key1=value1... form, then encrypt the resulting string using AES-CBC with PKCS5 Padding (16 bytes variant) using PasswordPassword as both the key and IV.&#xA;&#xA;Then you send {&#34;EncType&#34;: &#34;A&#34;, &#34;EncQuery&#34;: &#34;base64-encoded-encrypted-string&#34;}, and receive response from one of the .../API/Module/MethodName endpoints. The response will be JSON with no extra encryption, so it is definitely a deterrent against making requests, not a security feature.&#xA;&#xA;Login&#xA;&#xA;Armed with that knowledge, and some help from exposed API listing on one of the utility websites I found that I need to use ValidateUserLoginMob call expecting userid and password.&#xA;&#xA;However, password had to be base64-encoded result of applying a secret scheme from that SecurityConstant module above. It is always SHA256.&#xA;&#xA;So my first https://utility.example.net/API/UserLogin/ValidateUserLogin was a success, I got LoginToken and AccountNumber, which was all we needed to start poking APIs.&#xA;&#xA;Tada!&#xA;&#xA;If your utility uses SEW SCM, i.e. one of these at https://play.google.com/store/apps/developer?id=Smart+Energy+Water, you should be able to get API listing by visiting the web interface, and appending /API/Help. Or, if your utility runs an older version of SCM, replace /portal/ with /portalservice/UserLogin.svc/help or /portalservice/Usage.svc/help. You may get the .NET API definitions.]]&gt;</description>
      <content:encoded><![CDATA[<p>Once upon a time I learned about <a href="https://github.com/home-assistant/core/tree/dev/homeassistant/components/opower" rel="nofollow">Opower HomeAssistant integration</a>. But my utility does not use Opower, it was using something called “Smart Energy Water”.</p>

<p>Smart Energy Water, or <a href="/tildavaan/tag:SEW" class="hashtag" rel="nofollow"><span>#</span><span class="p-category">SEW</span></a> is a SaaS provider, and they ship the whole thing – the backend, frontend, and the phone apps, the latter under the name SCM, which means Smart Customer Mobile.</p>

<p>So I embarked on a journey to figure out how these phone apps worked and, if successful, get my data out and into homeassistant.</p>

<h1 id="apk">APK</h1>

<p>I pulled an APK of my utility from Google Play Store and found that something secret is hidden in a libnative-lib.so binary, under <code>com.sew.scm.gcm.SecureConstant</code>, under a few methods returning String, and some methods that decrypt these strings using a heavily obfuscated set of routines, which essentially XOR&#39;d (in case of Android APK) the values of <code>gcm_default_sender_id</code> + <code>google_app_id</code> + <code>Android_App_RatingConstant_File</code>, all the values from the <code>strings.xml</code> within the app resources.</p>

<p>One of the decoded tokens contains a key for request encryption. It was ...</p>

<h1 id="passwordpassword"><code>PasswordPassword</code></h1>

<p>SCM apps use private APIs. In order to remain private and hard to use the requests are encrypted.</p>

<p>You urlencode the parameters into <code>key=value&amp;key1=value1...</code> form, then encrypt the resulting string using AES-CBC with PKCS5 Padding (16 bytes variant) using <code>PasswordPassword</code> as both the <code>key</code> and <code>IV</code>.</p>

<p>Then you send <code>{&#34;EncType&#34;: &#34;A&#34;, &#34;EncQuery&#34;: &#34;base64-encoded-encrypted-string&#34;}</code>, and receive response from one of the <code>.../API/Module/MethodName</code> endpoints. The response will be JSON with no extra encryption, so it is definitely a deterrent against making requests, not a security feature.</p>

<h1 id="login">Login</h1>

<p>Armed with that knowledge, and some help from exposed API listing on one of the utility websites I found that I need to use <code>ValidateUserLoginMob</code> call expecting <code>userid</code> and <code>password</code>.</p>

<p>However, <code>password</code> had to be base64-encoded result of applying a secret scheme from that SecurityConstant module above. It is always <code>SHA256</code>.</p>

<p>So my first <code>https://utility.example.net/API/UserLogin/ValidateUserLogin</code> was a success, I got <code>LoginToken</code> and <code>AccountNumber</code>, which was all we needed to start poking APIs.</p>

<h1 id="tada">Tada!</h1>

<p>If your utility uses SEW SCM, i.e. one of these at <a href="https://play.google.com/store/apps/developer?id=Smart+Energy+Water" rel="nofollow">https://play.google.com/store/apps/developer?id=Smart+Energy+Water</a>, you should be able to get API listing by visiting the web interface, and appending /API/Help. Or, if your utility runs an older version of SCM, replace <code>/portal/</code> with <code>/portalservice/UserLogin.svc/help</code> or <code>/portalservice/Usage.svc/help</code>. You may get the .NET API definitions.</p>
]]></content:encoded>
      <guid>https://infosec.press/tildavaan/smart-energy-water-scm-api-secrets</guid>
      <pubDate>Tue, 15 Apr 2025 03:14:26 +0000</pubDate>
    </item>
  </channel>
</rss>